#include <os/kernelif.h>
#include <os/fs.h>
#include <os/fsal.h>
#include <os/task.h>
#include <os/driver.h>
#include <os/swap.h>
#include <os/schedule.h>
#include <driver/view/mouse.h>
#include <os/syscall.h>
#include <os/process.h>
#include <os/test.h>
#include<os/virmem.h>
#include <os/timer.h>
#include <os/debug.h>
#include <driver/view/view.h>
#include <lib/unistd.h>
#include <lib/type.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include<arch/memory.h>

/*
extern void AsmTest();
*/

#if 0
static void FsTest()
{
    int fd = KFileOpen("/test", O_CREATE | O_RDWR);
    if (fd < 0)
    {
        KPrint("[test] file create failed!\n");
        return 0;
    }
    uint32_t *w_buff = KMemAlloc(1024 * 4), *r_buff = KMemAlloc(1024 * 4);
    for (int i = 0; i < 1024; i++)
    {
        w_buff[i] = i;
    }
    memset(r_buff, 0, 1024 * 4);
    if (KFileWrite(fd, w_buff, 1024 * 4) < 0)
    {
        KPrint("[test] file write failed!\n");
        return;
    }
    KFileRewind(fd);
    if (KFileRead(fd, r_buff, 1024 * 4) < 0)
    {
        KPrint("[test] file read failed!\n");
        return;
    }
    if (memcmp(w_buff, r_buff, 1024 * 4))
    {
        KPrint("[test] fs r/w test err\n");
        return;
    }
    KPrint("[test] fixed r/w test ok\n");

    KFileRewind(fd);
    uint32_t seek1=KFileLSeek(fd,0,SEEK_SET);
    KPrint("seek1 %d\n",seek1);
    uint32_t seek2=KFileLSeek(fd,300,SEEK_SET);
    KPrint("seek2 %d\n",seek2);
    uint32_t seek3=KFileLSeek(fd,200,SEEK_CUR);
    KPrint("seek3 %d\n",seek3);
    uint32_t seek4=KFileLSeek(fd,400,SEEK_END);
    KPrint("seek4 %d\n",seek4);
    uint32_t seek5=KFileLSeek(fd,500,SEEK_END);
    KPrint("seek5 %d\n",seek5);
   /*  uint32_t seek6=KFileLSeek(fd,800,SEEK_CUR);
    KPrint("seek6 %d\n",seek6);
 */
    uint32_t pos=KFileFTell(fd);
    KPrint("pos %d\n",pos);

    seek1=KFileLSeek(fd,0,SEEK_SET);
    KPrint("seek1 %d\n",seek1);

    seek2=KFileLSeek(fd,80,SEEK_END);
    KPrint("seek2 %d\n",seek2);


    /*memset(r_buff, 0, 1024 * 4);
    if (KFileLSeek(fd, 20 * 4, SEEK_SET) < 0)
    {
        KPrint("[test] fs lseek err\n");
        return;
    }
    KFileRead(fd, r_buff, 5 * 4);
    if (memcmp(r_buff, &w_buff[20], 5 * 4))
    {
        KPrint("[test] fs r/w test err\n");
        return;
    }
    if (KFileLSeek(fd, 32 * 4, SEEK_SET) < 0)
    {
        KPrint("[test] fs lseek err\n");
        return;
    }
    KFileRead(fd, r_buff, 120 * 4);
    if (memcmp(r_buff, &w_buff[32], 120 * 4))
    {
        KPrint("[test] fs r/w test err\n");
        return;
    }
    KPrint("[test] fs rand read test ok\n");

    KFileRewind(fd);
    memset(w_buff, 0, 1024 * 4);
    memset(r_buff, 0, 1024 * 4);
    KFileWrite(fd, w_buff, 1024 * 4);
    KFileRewind(fd);
    KFileRead(fd, r_buff, 1024 * 4);
    if (memcmp(r_buff, w_buff, 1024 * 4))
    {
        KPrint("[test] fs r/w test err\n");
        return;
    }
    KPrint("[test] file clear ok\n");
    KFileClose(fd); */

    // memset(w_buff, 0, 1024 * 4);
    // memset(r_buff, 0, 1024 * 4);
    // for (int i = 0; i < 1024; i++)
    // {
    //     w_buff[i] = i;
    // }
    // KFileLSeek(fd, 512 * 4, SEEK_SET);
    // KFileWrite(fd, &w_buff[512], 200 * 4);
    // KFileLSeek(fd, 512 * 4, SEEK_SET);
    // KFileRead(fd, r_buff, 200 * 4);
    // if (memcmp(r_buff, &w_buff[512], 200 * 4))
    // {
    //     KPrint("[test] fs r/w test err\n");
    //     KFileClose(fd);
    //     return;
    // }
    // memset(r_buff,0,1024*4);
    // KFileLSeek(fd,200*4,SEEK_SET);
    // KFileRead(fd,r_buff,30*4);
    // if(memcmp(r_buff,&w_buff[200],30*4))
    // {
    //     KPrint("[test] fs r/w test err\n");
    //     KFileClose(fd);
    //     return;
    // }

    KPrint("[test] rand write test ok\n");
    KFileClose(fd);
}
#endif

/*static void TimerHandler1(void *arg)
{
    timer_t *timer = (timer_t *)arg;
    KPrint("[test] timer out! ticks %d\n", timer->timeout);
}

static void TimerHandler2(void *arg)
{
    timer_t *timer = (timer_t *)arg;
    KPrint("[test] timer out! ticks %d\n", timer->timeout);
}

static void TimerTest()
{
    timer_t *timer = TimerAlloc();
    if (!timer)
        return -1;
    TimerModify(timer, 20);
    TimerSetHandler(timer, TimerHandler1);
    TimerSetArgument(timer, timer);
    TimerAdd(timer);

    timer_t *timer1 = TimerAlloc();
    TimerModify(timer1, 50);
    TimerSetHandler(timer1, TimerHandler2);
    TimerSetArgument(timer1, timer1);
    TimerAdd(timer1);
    KPrint("timer create ok!\n");
    TimerDump();
}

static void TTYFun()
{
    int fd = SysOpen("/dev/tty0", 0);
    if (fd < 0)
    {
        KPrint("[tty] open error\n");
        return;
    }

    char buff[32];
    SysRead(fd, buff, 23);
    KPrint("tty read end\n");
    CPUhlt();
}

static void TTYTest()
{
    TaskCreate("tt", TASK_PRIOR_LEVEL_NORMAL, TTYFun, NULL);
    while (1)
        ;
}


static void SwapTest()
{
    uint8_t *page = KMemAlloc(PAGE_SIZE);
    if (!page)
    {
        KPrint("[swap] alloc err\n");
        return;
    }
    uint32_t data[PAGE_SIZE / 4];
    for (int i = 0; i < PAGE_SIZE / 4; i++)
    {
        data[i] = i;
    }
    memcpy(page, data, PAGE_SIZE);
    if (SwapOut(page) < 0)
    {
        KPrint("[swap] swap out err\n");
        return;
    }
    KPrint("[swap] swap out vpage %x ok\n", page);
    if (SwapIn(page) < 0)
        return;
    KPrint("[swap] swap in vpage %x ok\n", page);
    if (memcmp(page, data, PAGE_SIZE))
    {
        KPrint("[swap] check err\n");
        return;
    }
    KPrint("[swap] swap test ok\n");
}*/

#if 0

void ViewTest()
{
    KPrint("[view] open view\n");
     int flags = ((VIEW_TYPE_FLOAT & 0x1f) << 26) | ((1024 & 0x1fff) << 12) | (768 & 0x1fff);
    //int flags = ((VIEW_TYPE_FLOAT & 0x1f) << 26) | ((100 & 0x1fff) << 12) | (100 & 0x1fff);
    int view = DeviceOpen("view0", flags);
    if (!view)
    {
        KPrint("[view] create view err\n");
        return;
    }
    KPrint("[view] create view ok\n");
    uint32_t monitor = 1;
    uint32_t pos = (0 << 16) | 0;
    DeviceDevCtl(view, VIEWIO_SETPOS, &pos);
    DeviceDevCtl(view, VIEWIO_SHOW, NULL);
    DeviceDevCtl(view, VIEWIO_SETMONITOR, &monitor);
    view_rect_t rect = {0, 0, 100, 100};
    DeviceDevCtl(view, VIEWIO_SETWINMAXIMRECT, &rect);
    uint32_t vid;
    DeviceDevCtl(view,VIEWIO_GETVID,&vid);
    KPrint("[test] vid %d\n",vid);
  
    int view2=DeviceOpen("view1", flags);
    if(!view2)
    {
        KPrint("create view err\n");
        return;
    }
    KPrint("[view] create view ok\n");

    /*ViewSetXY(view_mouse.view, 20, 20);
    ViewSetXY(view_mouse.view,50,20);*/
    while (1)
        ;

    CPUhlt();
}

#endif 

#if 0
void PttyTest()
{
    int ptty1=DeviceOpen("ptm0",DEVICE_NOWAIT);
    if(!ptty1)
    {
        KPrint("[ptty test] open ptty error\n");
        return;
    }

    char buff[32]="hello world";
    //DeviceWrite(ptty1,buff,strlen(buff),0);

    DeviceDevCtl(ptty1,TTYIO_SETPTLOCK,0);
    int ptty2=DeviceOpen("pts0",DEVICE_NOWAIT);
    if(!ptty2)
    {
        KPrint("[ptty test] open ptty error\n");
        return;
    }

    char tbuff[32];
    memset(tbuff,0,32);

    /*int reads=DeviceRead(ptty2,tbuff,32,0);
    if(reads<0) 
    {
        KPrint("[ptty test] read error\n");
        return ;
    }
    KPrint("[ptty test] reads %d bytes,return %s\n",reads,tbuff);*/

    DeviceWrite(ptty2,buff,strlen(buff),0);

    //memset(tbuff,0,32);
    int reads=DeviceRead(0,tbuff,32,0);
    if(reads<0)
    {
        KPrint("[ptty test] read error\n");
        return ;
    }
    KPrint("[ptty test] reads %d bytes,return %s\n",reads,tbuff);
}
#endif

#if 0
void TicksTest()
{
    //KPrint("--ticks test===sys ticks %d\n",(uint32_t)sys_ticks);
    
    /*wmb();
    volatile uint64_t  ticks1=sys_ticks;
    volatile uint64_t tsc1=RdTsc();
    KPrint("ticks 1 %u tsc1 %u\n",(uint32_t)ticks1,(uint32_t)tsc1);
    Mdelay(1000);
    wmb();
    volatile uint64_t ticks2=sys_ticks;
    volatile uint64_t tsc2=RdTsc();
    KPrint("ticks2 %u tsc2 %u\n",(uint32_t)ticks2,(uint32_t)tsc2);
    KPrint("spend time %u ticks,tscs %u ticks\n",(uint32_t)(ticks2-ticks1),(uint32_t)(tsc2-tsc1));*/
}
#endif 

#if 0
void VirMemTest()
{
   uint32_t base1= VirBaseAlloc(32);
   KPrint("[test] alloc vbase at %x\n",base1);
   uint32_t base2=VirBaseAlloc(2048);
   KPrint("[test] alloc vbase at %x\n",base2);
   uint32_t base3=VirBaseAlloc(5000);
   KPrint("[test] alloc vbase at %x\n",base3);

   VirBaseFree(base1,32);
   uint32_t base4=VirBaseAlloc(5433);
   KPrint("[test] alloc vbase at %x\n",base4);

   uint32_t vbase=VirMemAlloc(32);
   if(vbase!=NULL)
    KPrint("[test] allo vmem at %x\n",vbase);

   uint32_t vbase1=VirMemAlloc(43);
   if(vbase1!=NULL)
    KPrint("[test] alloc vmem at %x\n",vbase1);
   uint32_t vbase2=VirMemAlloc(531);
   if(vbase2!=NULL)
    KPrint("[test] alloc vmem at %x\n",vbase2);

   int ret=VirMemFree(vbase);
   if(ret!=-1)
    KPrint("free vbase err %x\n",vbase);
   ret=VirMemFree(vbase2);
   if(ret!=-1)
    KPrint("free vbase err %x\n",vbase2);

   uint32_t pyaddr=AllocKernelPage(2);
   if(pyaddr==0)
    return ;
   uint32_t vaddr=MemIoReMap(pyaddr,2*4096);
   if(vaddr!=0)
    KPrint("ioremap vaddr at %x pyaddr at %x\n",vaddr,pyaddr);
   CPUhlt();
}
#endif 


// static void FileTest()
// {
//     int fd=KFileOpen("/test.txt",O_RDWR);
//     if(fd<0)
//     {
//         KPrint("open test failed\n");
//         return -1;
//     }
//     char *buffer="hello world\n";
//     uint32_t writes=KFileWrite(fd,buffer,strlen(buffer));
//     KPrint("write %d bytes\n",writes);
//     KFileClose(fd);
// }


static void task_func_1()
{
    while(1)
    {
        KPrint("task1");
    }
}

static void task_func_2()
{
    while(1)
    {
        KPrint("task2");
    }
}

static void task_func_3()
{
    while(1)
    {
        KPrint("task3");
    }
}

static void task_func_4()
{
    while(1)
    {
        KPrint("task4");
    }
}

static void task_func_5()
{
    while(1)
    {
        KPrint("task5");
    }
}


void TaskTest()
{
    // TaskCreate("task1",TASK_PRIOR_LEVEL_HIGH,task_func_1,NULL);
    // TaskCreate("task2",TASK_PRIOR_LEVEL_NORMAL,task_func_2,NULL);
    // TaskCreate("task3",TASK_PRIOR_LEVEL_LOW,task_func_3,NULL);
    // TaskCreate("task4",TASK_PRIOR_LEVEL_HIGH,task_func_4,NULL);
    // TaskCreate("task5",TASK_PRIOR_LEVEL_NORMAL,task_func_5,NULL);
    // TaskCreate("task6",TASK_PRIOR_LEVEL_LOW,task_func_6,NULL);
    // TaskCreate("task7",TASK_PRIOR_LEVEL_NORMAL,task_func_7,NULL);
    // TaskCreate("task8",TASK_PRIOR_LEVEL_LOW,task_func_8,NULL);
}

void Test()
{
    //TicksTest();
    //TaskCreate("test",TASK_PRIOR_LEVEL_NORMAL,TimerTest,NULL);
    //FsTest();
    //FileTest();
    //SwapTest();
    //AsmTest();
    //ViewTest();
    //CPUhlt();
    //PttyTest();
    //SysSleep(50);
    //VirMemTest();
    //Mdelay(20);
    //KPrint("delay ok\n");
    // TaskTest();
    // while(1);
}